package cn.rtplay.esp32camcar;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.WindowManager;
import android.webkit.WebSettings;
import android.webkit.WebViewClient;
import android.widget.PopupWindow;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.LinearLayoutCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.Lifecycle;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;

import com.uber.autodispose.AutoDispose;
import com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider;

import java.util.concurrent.TimeUnit;

import cn.rtplay.esp32camcar.databinding.ActivityOperationBinding;
import cn.rtplay.esp32camcar.databinding.CarLedLayoutBinding;
import cn.rtplay.esp32camcar.myView.BackDialog;
import cn.rtplay.esp32camcar.toolUtils.ConfUtil;
import cn.rtplay.esp32camcar.toolUtils.LogUtil;
import cn.rtplay.esp32camcar.toolUtils.NetworkUtils;
import cn.rtplay.esp32camcar.toolUtils.Tools;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;

/**
 * The type Operation activity.
 */
public class OperationActivity extends AppCompatActivity {

    private final String TAG = "OperationActivity";
    /**
     * The constant EXTRAS_DEV_ADDRESS.
     */
    public static final String EXTRAS_DEV_ADDRESS = "device_address";
    /**
     * The constant EXTRAS_CAR_NO.
     */
    public static final String EXTRAS_CAR_NO = "car_number";

    private LocalReceiver localReceiver;
    private LocalBroadcastManager localBroadcastManager;

    private final Context mContext = this;
    private ActivityOperationBinding mViewBinding;
    private ESP32UDPService mESP32UDPService;
    private UserData mUserSetting;
    private int lastSpeed = 0;
    private int lastChargeStatus = ESP32UDPService.CHARGING_STATUS_NOT_CHARGING; // 最后充电状态，做去重动作判断

    // Code to manage Service lifecycle.
    private final ServiceConnection mServiceConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder service) {
            LogUtil.v(TAG, "onServiceConnected in");
            mESP32UDPService = ((ESP32UDPService.LocalBinder) service).getService();
            // 初始化默认参数
            mESP32UDPService.initCorrectionAngle(mUserSetting.getUserSetting(UserData.PREFERENCES_SETTING_CORRECTION_ANGLE));
            // 图像质量 音效开关 音量值
            mESP32UDPService.initAVSetting(mUserSetting.getUserSetting(UserData.PREFERENCES_SETTING_IMAGE_QUALITY),
                    mUserSetting.getUserSetting(UserData.PREFERENCES_SETTING_SOUND) == UserData.VALUE_SOUND_OPEN,
                    mUserSetting.getUserSetting(UserData.PREFERENCES_SETTING_VOLUME));
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mESP32UDPService = null;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mViewBinding = ActivityOperationBinding.inflate(getLayoutInflater());
        setContentView(mViewBinding.getRoot());

        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        mUserSetting = new UserData(this);
        // 设置背景色
        setBackground(mUserSetting.getUserSetting(UserData.PREFERENCES_SETTING_UI_COLOR));
        // 方向控制方式
        setDirectionControlMode(mUserSetting.getUserSetting(UserData.PREFERENCES_SETTING_DIRECTION_CONTROL_MODE));
        // 档位控制方式
        setControlMode(mUserSetting.getUserSetting(UserData.PREFERENCES_SETTING_GEAR_CONTROL_MODE));

        final Intent intent = getIntent();
        String mCarNumber = intent.getStringExtra(EXTRAS_CAR_NO);
        String mDeviceAddress = intent.getStringExtra(EXTRAS_DEV_ADDRESS);
        LogUtil.d(TAG, "CarNO:" + mCarNumber);
        LogUtil.d(TAG, "wifi addr:" + mDeviceAddress);
        mViewBinding.carNO.setText(mCarNumber);
        // rtcar-redlykl-456123
        String carColor = ConfUtil.getInstance().findColorValue(mDeviceAddress.substring(6, 9));
        mViewBinding.carNO.setTextColor(Color.parseColor(carColor));
        String brand = ConfUtil.getInstance().findBrandName(mDeviceAddress.substring(9, 12));
        int carBrandId;
        if (brand != null) {
            int brandId = getResources().getIdentifier(brand, "raw", "cn.rtplay.esp32camcar");
            if (brandId != 0) {
                carBrandId = brandId;
            } else {
                carBrandId = getResources().getIdentifier("aodi", "raw", "cn.rtplay.esp32camcar");
            }
        } else {
            carBrandId = getResources().getIdentifier("aodi", "raw", "cn.rtplay.esp32camcar");
        }
        mViewBinding.carBrand.setImageResource(carBrandId);
        String model = ConfUtil.getInstance().findModelName(mDeviceAddress.substring(9, 12), mDeviceAddress.substring(12, 13));
        String carModel;
        if (model != null) {
            carModel = model;
        } else {
            carModel = "";
        }
        mViewBinding.carModel.setText(carModel);

        localBroadcastManager = LocalBroadcastManager.getInstance(this);
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(SettingActivity.BROADCAST_USER_SETTING);
        intentFilter.addAction(ESP32UDPService.BROADCAST_BATTERY_INFORMATION);
        localReceiver = new LocalReceiver();
        //注册本地接收器
        localBroadcastManager.registerReceiver(localReceiver, intentFilter);

        Intent esp32ServiceIntent = new Intent(this, ESP32UDPService.class);
        bindService(esp32ServiceIntent, mServiceConnection, BIND_AUTO_CREATE);

        mViewBinding.carLed.setOnClickListener(view -> showCarLEDPopupWindow());
        mViewBinding.setting.setOnClickListener(view -> {
            Intent intentSettingActivity = new Intent(OperationActivity.this, SettingActivity.class);
            startActivity(intentSettingActivity);
            overridePendingTransition(R.anim.right_in, 0);
        });
        mViewBinding.horn.setOnClickListener(view -> {
            mESP32UDPService.hornSound();
        });

        mViewBinding.start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mESP32UDPService.setStart(true);
                int cx = view.getWidth() / 2;
                int cy = view.getHeight() / 2;
                float radius = view.getWidth();
                Animator anim = ViewAnimationUtils.createCircularReveal(view, cx, cy, radius, 0);
                anim.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        super.onAnimationEnd(animation);
                        view.setVisibility(View.INVISIBLE);
                        LogUtil.d(TAG, "ssid:" + NetworkUtils.getWifiSSID(mContext));

                        ObjectAnimator leftAnimator = ObjectAnimator.ofFloat(mViewBinding.blockLeft, "translationX", 0, -(mViewBinding.blockLeft.getRight() - mViewBinding.blockLeft.getLeft()));
                        leftAnimator.setDuration(2000);
                        leftAnimator.start();
                        ObjectAnimator rightAnimator = ObjectAnimator.ofFloat(mViewBinding.blockRight, "translationX", 0, (mViewBinding.blockRight.getRight() - mViewBinding.blockRight.getLeft()));
                        rightAnimator.setDuration(2000);
                        rightAnimator.start();
                    }
                });
                anim.start();
//                // 设置mainView的ip,xml中需要设置android:layout_height="0dp"
//                mViewBinding.mainView.setAdjustHeight(true);
//                // mViewBinding.mainView.setAdjustWidth(true);
//                mViewBinding.mainView.setMode(MjpegView.MODE_FIT_WIDTH);
//                //mViewBinding.mainView.setMsecWaitAfterReadImageError(1000);
//                mViewBinding.mainView.setUrl("http://192.168.4.1:81/stream");
//                mViewBinding.mainView.setRecycleBitmap(true);
//                mViewBinding.mainView.startStream();

                WebSettings WebSet = mViewBinding.mainView.getSettings();    //获取webview设置
                WebSet.setUseWideViewPort(true);        //扩大比例的缩放
                WebSet.setLoadWithOverviewMode(true);   //宽度自适应
                String newUA = "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.4) Gecko/20100101 Firefox/4.0";
                mViewBinding.mainView.getSettings().setUserAgentString(newUA);// 修正网络头太长的问题
                mViewBinding.mainView.loadUrl("http://192.168.4.1:81/stream");
                mViewBinding.mainView.setWebViewClient(new WebViewClient());
            }
        });

    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    protected void onPause() {
//        mViewBinding.mainView.stopStream();
        super.onPause();
    }

    @Override
    protected void onStop() {
//        mViewBinding.mainView.stopStream();
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        localBroadcastManager.unregisterReceiver(localReceiver);
//        mViewBinding.mainView.stopStream();
        super.onDestroy();
        stopSpeedChange();
        stopChargingTextUpdate();
    }

    private long exitTime = 0;

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK
                && event.getAction() == KeyEvent.ACTION_DOWN) {
            if ((System.currentTimeMillis() - exitTime) > 1000) {
                exitTime = System.currentTimeMillis();
            } else {
                new BackDialog(this).Builder()
                        .setOnConfirmClickListener(c -> {
                            mESP32UDPService.setStart(false);
                            Tools.exitApp(c);
                        })
                        .setOnCancelClickListener(c -> LogUtil.d(TAG, "onClick: Cancel in"))
                        .setCancelText(getString(R.string.cancel))
                        .setConfirmText(getString(R.string.quit))
                        .setTitleText(getString(R.string.dialog_title_edit));
            }
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    private PopupWindow mPopWindow;
    private Disposable timerDisposable; // 侧拉框收回定时器

    private void showCarLEDPopupWindow() {
        //设置contentView
        CarLedLayoutBinding viewBinding = CarLedLayoutBinding.inflate(getLayoutInflater());
        mPopWindow = new PopupWindow(viewBinding.getRoot(),
                LinearLayoutCompat.LayoutParams.WRAP_CONTENT, LinearLayoutCompat.LayoutParams.WRAP_CONTENT, false);
        mPopWindow.setContentView(viewBinding.getRoot());
        // 初始化状态
        if (CarLedStatus.getInstance().getTurnLight() == CarLedStatus.LIGHT_LEFT) {
            viewBinding.turnLeft.setBackgroundResource(R.drawable.turn_left_on);
        } else if (CarLedStatus.getInstance().getTurnLight() == CarLedStatus.LIGHT_RIGHT) {
            viewBinding.turnRight.setBackgroundResource(R.drawable.turn_right_on);
        } else if (CarLedStatus.getInstance().getTurnLight() == CarLedStatus.LIGHT_WARNING) {
            viewBinding.warning.setBackgroundResource(R.drawable.warning_down);
        }
        if (CarLedStatus.getInstance().isWidthLight()) {
            viewBinding.outline.setBackgroundResource(R.drawable.outline_light_on);
        }
        if (CarLedStatus.getInstance().getHeadLights() == CarLedStatus.LIGHT_FAR) {
            viewBinding.far.setBackgroundResource(R.drawable.far_light_on);
        } else if (CarLedStatus.getInstance().getHeadLights() == CarLedStatus.LIGHT_NEAR) {
            viewBinding.near.setBackgroundResource(R.drawable.near_light_on);
        } else if (CarLedStatus.getInstance().getHeadLights() == CarLedStatus.LIGHT_AUTO) {
            viewBinding.auto.setBackgroundResource(R.drawable.auto_light_on);
        }

        // 设置各个控件的点击响应
        viewBinding.turnLeft.setOnClickListener(view -> {
            resetDismissPopupWindow();
            if (CarLedStatus.getInstance().getTurnLight() == CarLedStatus.LIGHT_LEFT) {
                viewBinding.turnLeft.setBackgroundResource(R.drawable.turn_left_off);
                CarLedStatus.getInstance().setTurnLight(CarLedStatus.LIGHT_NONE);
                mESP32UDPService.setCarLight(CarLedStatus.LIGHT_LEFT, false);
            } else {
                viewBinding.turnLeft.setBackgroundResource(R.drawable.turn_left_on);
                viewBinding.turnRight.setBackgroundResource(R.drawable.turn_right_off);
                viewBinding.warning.setBackgroundResource(R.drawable.warning_up);
                CarLedStatus.getInstance().setTurnLight(CarLedStatus.LIGHT_LEFT);
                mESP32UDPService.setCarLight(CarLedStatus.LIGHT_LEFT, true);
            }
        });
        viewBinding.turnRight.setOnClickListener(view -> {
            resetDismissPopupWindow();
            if (CarLedStatus.getInstance().getTurnLight() == CarLedStatus.LIGHT_RIGHT) {
                viewBinding.turnRight.setBackgroundResource(R.drawable.turn_right_off);
                CarLedStatus.getInstance().setTurnLight(CarLedStatus.LIGHT_NONE);
                mESP32UDPService.setCarLight(CarLedStatus.LIGHT_RIGHT, false);
            } else {
                viewBinding.turnLeft.setBackgroundResource(R.drawable.turn_left_off);
                viewBinding.turnRight.setBackgroundResource(R.drawable.turn_right_on);
                viewBinding.warning.setBackgroundResource(R.drawable.warning_up);
                CarLedStatus.getInstance().setTurnLight(CarLedStatus.LIGHT_RIGHT);
                mESP32UDPService.setCarLight(CarLedStatus.LIGHT_RIGHT, true);
            }
        });
        viewBinding.warning.setOnClickListener(view -> {
            resetDismissPopupWindow();
            if (CarLedStatus.getInstance().getTurnLight() == CarLedStatus.LIGHT_WARNING) {
                viewBinding.warning.setBackgroundResource(R.drawable.warning_up);
                CarLedStatus.getInstance().setTurnLight(CarLedStatus.LIGHT_NONE);
                mESP32UDPService.setCarLight(CarLedStatus.LIGHT_WARNING, false);
            } else {
                viewBinding.turnLeft.setBackgroundResource(R.drawable.turn_left_off);
                viewBinding.turnRight.setBackgroundResource(R.drawable.turn_right_off);
                viewBinding.warning.setBackgroundResource(R.drawable.warning_down);
                CarLedStatus.getInstance().setTurnLight(CarLedStatus.LIGHT_WARNING);
                mESP32UDPService.setCarLight(CarLedStatus.LIGHT_WARNING, true);
            }
        });
        viewBinding.outline.setOnClickListener(view -> {
            resetDismissPopupWindow();
            if (CarLedStatus.getInstance().isWidthLight()) {
                viewBinding.outline.setBackgroundResource(R.drawable.outline_light_off);
                CarLedStatus.getInstance().setWidthLight(false);
                mESP32UDPService.setCarLight(CarLedStatus.LIGHT_WIDTH, false);
            } else {
                viewBinding.outline.setBackgroundResource(R.drawable.outline_light_on);
                CarLedStatus.getInstance().setWidthLight(true);
                mESP32UDPService.setCarLight(CarLedStatus.LIGHT_WIDTH, true);
            }
        });
        viewBinding.far.setOnClickListener(view -> {
            resetDismissPopupWindow();
            if (CarLedStatus.getInstance().getHeadLights() == CarLedStatus.LIGHT_FAR) {
                viewBinding.far.setBackgroundResource(R.drawable.far_light_off);
                CarLedStatus.getInstance().setHeadLights(CarLedStatus.LIGHT_NONE);
                mESP32UDPService.setCarLight(CarLedStatus.LIGHT_FAR, false);
            } else {
                viewBinding.far.setBackgroundResource(R.drawable.far_light_on);
                viewBinding.near.setBackgroundResource(R.drawable.near_light_off);
                viewBinding.auto.setBackgroundResource(R.drawable.auto_light_off);
                CarLedStatus.getInstance().setHeadLights(CarLedStatus.LIGHT_FAR);
                mESP32UDPService.setCarLight(CarLedStatus.LIGHT_FAR, true);
            }
        });
        viewBinding.near.setOnClickListener(view -> {
            resetDismissPopupWindow();
            if (CarLedStatus.getInstance().getHeadLights() == CarLedStatus.LIGHT_NEAR) {
                viewBinding.near.setBackgroundResource(R.drawable.near_light_off);
                CarLedStatus.getInstance().setHeadLights(CarLedStatus.LIGHT_NONE);
                mESP32UDPService.setCarLight(CarLedStatus.LIGHT_NEAR, false);
            } else {
                viewBinding.far.setBackgroundResource(R.drawable.far_light_off);
                viewBinding.near.setBackgroundResource(R.drawable.near_light_on);
                viewBinding.auto.setBackgroundResource(R.drawable.auto_light_off);
                CarLedStatus.getInstance().setHeadLights(CarLedStatus.LIGHT_NEAR);
                mESP32UDPService.setCarLight(CarLedStatus.LIGHT_NEAR, true);
            }
        });
        viewBinding.auto.setOnClickListener(view -> {
            resetDismissPopupWindow();
            if (CarLedStatus.getInstance().getHeadLights() == CarLedStatus.LIGHT_AUTO) {
                viewBinding.auto.setBackgroundResource(R.drawable.auto_light_off);
                CarLedStatus.getInstance().setHeadLights(CarLedStatus.LIGHT_NONE);
                mESP32UDPService.setCarLight(CarLedStatus.LIGHT_AUTO, false);
            } else {
                viewBinding.far.setBackgroundResource(R.drawable.far_light_off);
                viewBinding.near.setBackgroundResource(R.drawable.near_light_off);
                viewBinding.auto.setBackgroundResource(R.drawable.auto_light_on);
                CarLedStatus.getInstance().setHeadLights(CarLedStatus.LIGHT_AUTO);
                mESP32UDPService.setCarLight(CarLedStatus.LIGHT_AUTO, true);
            }
        });

        //显示PopupWindow
        mPopWindow.setBackgroundDrawable(null);
        mPopWindow.setAnimationStyle(R.style.carLedMenuAnim);
        mPopWindow.showAsDropDown(mViewBinding.carLed, 0, -mViewBinding.carLed.getHeight());
        dismissPopupWindow();
    }

    // 收起侧拉框定时
    private void dismissPopupWindow() {
        timerDisposable = Observable.timer(3000, TimeUnit.MILLISECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .as(AutoDispose.autoDisposable(AndroidLifecycleScopeProvider.from(this, Lifecycle.Event.ON_DESTROY)))
                .subscribe(aLong -> mPopWindow.dismiss());
    }

    // 重置测拉框收起定时
    private void resetDismissPopupWindow() {
        if (timerDisposable != null && !timerDisposable.isDisposed()) {
            timerDisposable.dispose();
        }
        dismissPopupWindow();
    }

    private void setBackground(int colorIndex) {
        switch (colorIndex) {
            case UserData.VALUE_UI_COLOR_GREY:
                mViewBinding.operationPager.setBackgroundColor(ContextCompat.getColor(this, R.color.grey));
                mViewBinding.blockLeft.setBackgroundColor(ContextCompat.getColor(this, R.color.grey));
                mViewBinding.blockRight.setBackgroundColor(ContextCompat.getColor(this, R.color.grey));
                break;
            case UserData.VALUE_UI_COLOR_DARKSLATEGRAY:
                mViewBinding.operationPager.setBackgroundColor(ContextCompat.getColor(this, R.color.darkslategray));
                mViewBinding.blockLeft.setBackgroundColor(ContextCompat.getColor(this, R.color.darkslategray));
                mViewBinding.blockRight.setBackgroundColor(ContextCompat.getColor(this, R.color.darkslategray));
                break;
            case UserData.VALUE_UI_COLOR_MIDNIGHTBLUE:
                mViewBinding.operationPager.setBackgroundColor(ContextCompat.getColor(this, R.color.midnightblue));
                mViewBinding.blockLeft.setBackgroundColor(ContextCompat.getColor(this, R.color.midnightblue));
                mViewBinding.blockRight.setBackgroundColor(ContextCompat.getColor(this, R.color.midnightblue));
                break;
            case UserData.VALUE_UI_COLOR_SLATEBLUE:
                mViewBinding.operationPager.setBackgroundColor(ContextCompat.getColor(this, R.color.slateblue));
                mViewBinding.blockLeft.setBackgroundColor(ContextCompat.getColor(this, R.color.slateblue));
                mViewBinding.blockRight.setBackgroundColor(ContextCompat.getColor(this, R.color.slateblue));
                break;
            case UserData.VALUE_UI_COLOR_SIENNA:
                mViewBinding.operationPager.setBackgroundColor(ContextCompat.getColor(this, R.color.sienna));
                mViewBinding.blockLeft.setBackgroundColor(ContextCompat.getColor(this, R.color.sienna));
                mViewBinding.blockRight.setBackgroundColor(ContextCompat.getColor(this, R.color.sienna));
                break;
            case UserData.VALUE_UI_COLOR_BLACK:
            default:
                mViewBinding.operationPager.setBackgroundColor(ContextCompat.getColor(this, R.color.black));
                mViewBinding.blockLeft.setBackgroundColor(ContextCompat.getColor(this, R.color.black));
                mViewBinding.blockRight.setBackgroundColor(ContextCompat.getColor(this, R.color.black));
        }
    }

    private void setDirectionControlMode(int mode) {
        LogUtil.v(TAG, "setDirectionControlMode:" + mode);
        if (mode == UserData.VALUE_DIRECTION_CONTROL_MODE_SENSOR) {
            SteeringDiagramFragment steeringDiagramFragment = new SteeringDiagramFragment();
            FragmentManager fragmentManagerLeft = getSupportFragmentManager();
            FragmentTransaction fragmentTransactionLeft = fragmentManagerLeft.beginTransaction();
            fragmentTransactionLeft.replace(R.id.fragment_left, steeringDiagramFragment, "LEFT");
            fragmentTransactionLeft.commitAllowingStateLoss();
        } else {
            SteeringWheelFragment steeringWheelFragment = new SteeringWheelFragment(mUserSetting.updateUserSetting(UserData.PREFERENCES_SETTING_STEERING_WHEEL_STYLE));
            FragmentManager fragmentManagerLeft = getSupportFragmentManager();
            FragmentTransaction fragmentTransactionLeft = fragmentManagerLeft.beginTransaction();
            fragmentTransactionLeft.replace(R.id.fragment_left, steeringWheelFragment, "LEFT");
            fragmentTransactionLeft.commitAllowingStateLoss();
        }
    }

    private void setControlMode(int mode) {
        if (mode == UserData.VALUE_GEAR_CONTROL_MODE_AUTO) {
            GearAutoFragment gearAutoFragment = new GearAutoFragment();
            FragmentManager fragmentManager = getSupportFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            fragmentTransaction.replace(R.id.fragment_right, gearAutoFragment, "RIGHT");
            fragmentTransaction.commitAllowingStateLoss();
        } else {
            GearManualFragment gearManualFragment = new GearManualFragment();
            FragmentManager fragmentManagerRight = getSupportFragmentManager();
            FragmentTransaction fragmentTransactionRight = fragmentManagerRight.beginTransaction();
            fragmentTransactionRight.replace(R.id.fragment_right, gearManualFragment, "RIGHT");
            fragmentTransactionRight.commitAllowingStateLoss();
        }
    }

    private class LocalReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            LogUtil.v(TAG, "onReceive:" + intent.getAction());
            if (intent.getAction().equals(SettingActivity.BROADCAST_USER_SETTING)) {
                LogUtil.d(TAG, "user setting key:" + intent.getExtras().getString(SettingActivity.BROADCAST_SETTING_KEY) + ":value:" + intent.getExtras().getInt(SettingActivity.BROADCAST_SETTING_VALUE));
                switch (intent.getExtras().getString(SettingActivity.BROADCAST_SETTING_KEY)) {
                    case UserData.PREFERENCES_SETTING_DIRECTION_CONTROL_MODE:
                        setDirectionControlMode(intent.getExtras().getInt(SettingActivity.BROADCAST_SETTING_VALUE));
                        break;
                    case UserData.PREFERENCES_SETTING_STEERING_WHEEL_STYLE:
                        if (mUserSetting.updateUserSetting(UserData.PREFERENCES_SETTING_DIRECTION_CONTROL_MODE) == UserData.VALUE_DIRECTION_CONTROL_MODE_MANUAL) {
                            setDirectionControlMode(UserData.VALUE_DIRECTION_CONTROL_MODE_MANUAL);
                        }
                        break;
                    case UserData.PREFERENCES_SETTING_GEAR_CONTROL_MODE:
                        setControlMode(intent.getExtras().getInt(SettingActivity.BROADCAST_SETTING_VALUE));
                        break;
                    case UserData.PREFERENCES_SETTING_IMAGE_QUALITY:
                        mESP32UDPService.setImageQuality(intent.getExtras().getInt(SettingActivity.BROADCAST_SETTING_VALUE));
                        break;
                    case UserData.PREFERENCES_SETTING_SOUND:
                        mESP32UDPService.setSoundEnable(intent.getExtras().getInt(SettingActivity.BROADCAST_SETTING_VALUE) == UserData.VALUE_SOUND_OPEN);
                        break;
                    case UserData.PREFERENCES_SETTING_VOLUME:
                        mESP32UDPService.setVolume(intent.getExtras().getInt(SettingActivity.BROADCAST_SETTING_VALUE));
                        break;
                    case UserData.PREFERENCES_SETTING_UI_COLOR:
                        setBackground(intent.getExtras().getInt(SettingActivity.BROADCAST_SETTING_VALUE));
                        break;
                }
            } else if (intent.getAction().equals(ESP32UDPService.BROADCAST_BATTERY_INFORMATION)) {
                LogUtil.d(TAG, "battery information:" + intent.getExtras().getInt(ESP32UDPService.BROADCAST_ELECTRICITY) +
                        "|charging:" + intent.getExtras().getInt(ESP32UDPService.BROADCAST_CHARGING) +
                        "|speed:" + intent.getExtras().getInt(ESP32UDPService.BROADCAST_SPEED));
                int rawValue = intent.getExtras().getInt(ESP32UDPService.BROADCAST_SPEED);
                int currSpeed = (short) (rawValue & 0xFFFF);
                int chargeStatus = intent.getExtras().getInt(ESP32UDPService.BROADCAST_CHARGING);
                int electricity = intent.getExtras().getInt(ESP32UDPService.BROADCAST_ELECTRICITY);
                if (electricity > 100) electricity = 100;
                mViewBinding.energy.setProgress(electricity);
                mViewBinding.energy.setEmptyVisibility(View.GONE);
                startSpeedChange(lastSpeed, currSpeed);
                lastSpeed = currSpeed;
                if (chargeStatus != lastChargeStatus) {
                    lastChargeStatus = chargeStatus;
                    if (chargeStatus == ESP32UDPService.CHARGING_STATUS_NOT_CHARGING) {
                        // 如果不是充电状态了，停止更新充电提示文本的逻辑
                        stopChargingTextUpdate();
                        mViewBinding.charge.setVisibility(View.GONE);
                    } else if (chargeStatus == ESP32UDPService.CHARGING_STATUS_CHARGING) {
                        // 启动充电提示文本的更新逻辑
                        LogUtil.e(TAG, " start charging text update");
                        mViewBinding.charge.setVisibility(View.VISIBLE);
                        mViewBinding.charge.setTextColor(ContextCompat.getColor(mContext, R.color.colorYellow));
                        startChargingTextUpdate();
                    } else if (chargeStatus == ESP32UDPService.CHARGING_STATUS_CHARGING_FULL) {
                        // 如果不是充电状态了，停止更新充电提示文本的逻辑
                        stopChargingTextUpdate();
                        mViewBinding.charge.setVisibility(View.VISIBLE);
                        mViewBinding.charge.setTextColor(ContextCompat.getColor(mContext, R.color.colorGreen));
                        mViewBinding.charge.setText(R.string.charged);
                    }
                }
            }
        }
    }

    // 用于实现充电过程中屏幕文字变化
    // 用于记录当前显示的充电提示文本的索引，初始化为0，表示从charging1开始
    private int currentChargingTextIndex = 0;
    // 定义一个数组来存储充电提示文本对应的资源ID，方便按顺序获取和切换显示内容
    private final int[] chargingTextResIds = {
            R.string.charging1,
            R.string.charging2,
            R.string.charging3,
            R.string.charging4
    };
    // 每秒更新一次，所以更新间隔是1000毫秒
    private static final int CHARGE_UPDATE_INTERVAL = 1000;
    // 使用Handler来实现定时更新
    private final Handler chargeTextHandler = new Handler();

    private final Runnable updateChargingTextRunnable = new Runnable() {
        @Override
        public void run() {
            // 根据当前索引获取对应的充电提示文本资源ID
            int resId = chargingTextResIds[currentChargingTextIndex];
            mViewBinding.charge.setText(resId);
            // 更新索引，准备显示下一个充电提示文本
            currentChargingTextIndex++;
            if (currentChargingTextIndex >= chargingTextResIds.length) {
                // 如果索引超出了数组范围，说明已经循环完一轮，重置为0，从头开始循环
                currentChargingTextIndex = 0;
            }
            // 继续发送更新消息，实现每秒循环更新
            chargeTextHandler.postDelayed(updateChargingTextRunnable, CHARGE_UPDATE_INTERVAL);
        }
    };

    // 启动更新充电提示文本的逻辑
    public void startChargingTextUpdate() {
        currentChargingTextIndex = 0;
        mViewBinding.charge.setText(R.string.charging1);
        chargeTextHandler.postDelayed(updateChargingTextRunnable, CHARGE_UPDATE_INTERVAL);
    }

    // 停止更新充电提示文本的逻辑
    public void stopChargingTextUpdate() {
        chargeTextHandler.removeCallbacks(updateChargingTextRunnable);
    }


    // 用于更改车速的定时实现
    // 记录当前速度值
    int currentSpeed;
    // 目标速度值（假设已经有了赋值的地方，这里仅示意）
    int targetSpeed;
    // 用于控制每次变化的步长，每秒变化10次，总共1秒，那么每次变化就是差值的1/10
    float step;
    // 用于记录已经变化的次数，达到10次就完成一次从当前到目标的变化
    int changeCount = 0;
    // 每秒变化20次，所以更新间隔是1000毫秒（1秒） / 20 = 50毫秒
    private static final int SPEED_UPDATE_INTERVAL = 50;
    // 使用Handler来实现定时更新
    private final Handler speedChangeHandler = new Handler();

    public void startSpeedChange(int newCurrentSpeed, int newTargetSpeed) {
        currentSpeed = newCurrentSpeed;
        targetSpeed = newTargetSpeed;
        // 计算步长
        step = (float) (targetSpeed - currentSpeed) / 20;
        changeCount = 0;
        // 发送第一个更新消息
        speedChangeHandler.postDelayed(updateSpeedRunnable, SPEED_UPDATE_INTERVAL);
    }

    private final Runnable updateSpeedRunnable = new Runnable() {
        @Override
        public void run() {
            // 按照步长更新当前速度值
            currentSpeed += (int) step;
            changeCount++;
            // 根据当前速度值更新界面显示（这里调用setText方法）
            String speedText = getString(R.string.curr_speed, currentSpeed);
            mViewBinding.speedShow.setText(speedText);
            if (changeCount < 10) {
                // 如果还没更新完10次，继续发送更新消息
                speedChangeHandler.postDelayed(updateSpeedRunnable, SPEED_UPDATE_INTERVAL);
            }
        }
    };

    public void stopSpeedChange() {
        speedChangeHandler.removeCallbacks(updateSpeedRunnable);
    }
}
